#pragma once

#include <wlr/backend.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/render/allocator.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_xdg_activation_v1.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_idle.h>
#include <wlr/types/wlr_idle_inhibit_v1.h>
#include <wlr/types/wlr_input_inhibitor.h>
#include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_output_management_v1.h>
#include <wlr/types/wlr_input_method_v2.h>
#include <wlr/types/wlr_text_input_v3.h>

typedef struct Cursor Cursor;
typedef struct KeyboardManager KeyboardManager;
typedef struct Seat Seat;
typedef struct Server Server;
typedef struct Monitor Monitor;
typedef struct Xdg_shell Xdg_shell;
typedef struct Xdg_decoration Xdg_decoration;
typedef struct Client Client;

#include "cursor.h"
#include "keyboard_manager.h"
#include "seat.h"
#include "monitor.h"
#include "xdg_shell.h"
#include "xdg_decoration.h"
#include "client.h"

enum {
    LyrBg,
    LyrBottom,
    LyrTop,
    LyrOverlay,
    LyrTile,
    LyrFloat,
    LyrNoFocus,
    LyrInputPopup,
    NUM_LAYERS
}; /* scene layers */

/**
 * The relay structure manages the relationship between text-input and
 * input_method interfaces on a given seat. Multiple text-input interfaces may
 * be bound to a relay, but at most one will be focused (receiving events) at
 * a time. At most one input-method interface may be bound to the seat. The
 * relay manages life cycle of both sides. When both sides are present and
 * focused, the relay passes messages between them.
 *
 * Text input focus is a subset of keyboard focus - if the text-input is
 * in the focused state, wl_keyboard sent an enter as well. However, having
 * wl_keyboard focused doesn't mean that text-input will be focused.
 */
struct input_method_relay {
    struct wl_list text_inputs; // dwl_text_input::link
    struct wlr_input_method_v2 *input_method; // doesn't have to be present

    struct wl_listener text_input_new;

    struct wl_listener input_method_new;
    struct wl_listener input_method_commit;
    struct wl_listener input_method_destroy;
    struct wl_listener input_method_new_popup_surface;
    struct wl_listener input_method_grab_keyboard;
    struct wl_listener input_method_keyboard_grab_destroy;
};

typedef struct Server
{
    struct wl_display *dpy;
    struct wlr_backend *backend;
    struct wlr_scene *scene;
    struct wlr_scene_node *layers[NUM_LAYERS];
    struct wlr_renderer *drw;
    struct wlr_allocator *alloc;
    struct wlr_compositor *compositor;

    Xdg_shell *xdg_shell;
    Xdg_decoration *xdg_decoration;

    struct wlr_xdg_activation_v1 *activation;
    struct wl_listener request_activate;

    struct wlr_output_layout *output_layout;
    struct wl_listener layout_change;

    struct wl_list mons;
    Monitor *selmon;
    struct wl_listener new_output;

//    struct wl_list clients; /* tiling order */
//    struct wl_list fstack;  /* focus order */

    struct wlr_idle *idle;
    struct wlr_idle_inhibit_manager_v1 *idle_inhibit_mgr;
    struct wl_listener idle_inhibitor_create;

    struct wlr_layer_shell_v1 *layer_shell;
    struct wl_listener new_layer_shell_surface;

    struct wlr_input_inhibit_manager *input_inhibit_mgr;

    Cursor *cursor;
    KeyboardManager *keyboard_manager;

    struct wl_listener new_input;

    Seat *seat;

    struct wlr_output_manager_v1 *output_mgr;
    struct wl_listener output_mgr_apply;
    struct wl_listener output_mgr_test;

    struct wlr_input_method_manager_v2 *input_method_manager;
    struct wlr_text_input_manager_v3 *text_input_manager;
    struct input_method_relay *input_relay;

    unsigned int cursor_mode;
    Client *grabc;
    int grabcx;
    int grabcy;

} Server;

Server *server_create(void);

void server_free(Server* server);

void server_run(Server* server, const char *startup_cmd);

void server_quit(Server* server);
